package com.shk.service.imp;

import com.alibaba.dubbo.config.annotation.Service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.shk.constant.RedisConstant;
import com.shk.dao.CheckGroupDao;
import com.shk.dao.SetmealDao;
import com.shk.entity.PageResult;
import com.shk.pojo.CheckGroup;
import com.shk.pojo.Setmeal;
import com.shk.service.SetmealService;
import com.shk.service.bloomfilter.BloomFileter;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service(interfaceClass = SetmealService.class)
@Transactional
public class SetmealServiceImpl implements SetmealService {
    @Autowired
    private SetmealDao setmealDao;
    @Autowired
    private JedisPool jedisPool;
    @Autowired
    private CheckGroupDao checkGroupDao;


    private BloomFileter bloomFileter = new BloomFileter(7000);

    //查询数据库中的套餐信息，并保存到redis中
    public void saveRedis() throws JsonProcessingException {
        Jedis jedis = jedisPool.getResource();
        ObjectMapper mapper = new ObjectMapper();

        List<Setmeal> setmeals = setmealDao.mobileFindAll();

        if (setmeals.size() > 0) {

            //将数据库中查询出的数据添加到布隆过滤器中
            setmeals.forEach(s -> bloomFileter.add(s.getId().toString()));

            for (Setmeal setmeal : setmeals) {

                Integer sm_id = setmeal.getId();
                //获取套餐对应的检查组信息,并设置给setmeal对象
                List<Integer> ck_ids = setmealDao.findSetmealAndCheckGroup(sm_id);
                List<CheckGroup> checkGroups = new ArrayList<>();
                if (ck_ids.size() > 0) {
                    for (Integer ck_id : ck_ids) {
                        CheckGroup checkGroup = checkGroupDao.findById(ck_id);
                        checkGroups.add(checkGroup);
                    }
                    setmeal.setCheckGroups(checkGroups);
                }
                String sm_id_str = String.valueOf(sm_id);
                //将数据库中查询出的setmeal对象序列化成json
                String setmeal_json = mapper.writeValueAsString(setmeal);
                jedis.hset("setmeals", sm_id_str, setmeal_json);
            }
            System.out.println("saveRedis被调用了！！----saveRedis");
        }

    }

//=========================！！！！！！！！！=========================

    //添加套餐
    public void add(Setmeal setmeal, Integer[] checkgroupIds) throws Exception {
        Jedis jedis = jedisPool.getResource();
        ObjectMapper mapper = new ObjectMapper();

        setmealDao.add(setmeal);
        Integer sm_id = setmeal.getId();
        this.setSetmealAndCheckGroup(sm_id, checkgroupIds);

        //查询数据库，并将套餐信息添加到redis中
        this.saveRedis();


        //将套餐图片添加到redis中
        String fileName = setmeal.getImg();
        jedis.sadd(RedisConstant.SETMEAL_PIC_DB_RESOURCES, fileName);
    }

//===================================================================

    @Override
    public PageResult findAll(Integer currentPage, Integer pageSize, String queryString) {
        PageHelper.startPage(currentPage, pageSize);
        Page<Setmeal> page = setmealDao.findAll(queryString);
        List<Setmeal> rows = page.getResult();
        long total = page.getTotal();
        return new PageResult(total, rows);
    }

//========================！！！！！！！================================

    //根据套餐id删除套餐（t_setmeal）及对应的检查组id（t_setmeal_checkgroup）
    public void delete(Integer id) throws JsonProcessingException {
        Jedis jedis = jedisPool.getResource();

        //删除套餐之前先查询数据库，将setmeal的信息保存到redis中
        Map<String, String> setmeals = jedis.hgetAll("setmeals");
        if (setmeals.size() == 0) {
            saveRedis();
        }
        setmealDao.deleteSetmealAndCheckGroup(id);
        setmealDao.delete(id);

        //先删除redis中对应的相关信息
        //将套餐id转换成字符串，即为redis中setmeal数据对应的字段
        String sm_id_str = String.valueOf(id);
        jedis.hdel("setmeals", sm_id_str);
        System.out.println("redis中对应id为" + sm_id_str + "的套餐信息也删除了！------delete");
    }

//===========================!!!!!!!=================================

    public Setmeal findById(Integer id) throws IOException {
        Jedis jedis = jedisPool.getResource();
        ObjectMapper mapper = new ObjectMapper();

        //先去redis中获取相应的套餐信息，若无再去布隆过滤器中获取，布隆过滤器中没有再从mysql中获取
        String sm_id_str = String.valueOf(id);
        String setmeal_json = jedis.hget("setmeals", sm_id_str);
        if (setmeal_json.length() > 0) {
            //redis中有Setmeal信息,返回redis中的信息
            Setmeal setmeal = mapper.readValue(setmeal_json, Setmeal.class);
            System.out.println("从redis中获取的setmeal！------findById");
            return setmeal;
        } else {
            //redis中没有该条数据
            boolean check = bloomFileter.check(id.toString());
            if (check) {
                //布隆过滤器中存在该key，则数据库中一定存在对应的数据，则查询数据库返回数据
                return setmealDao.findById(id);
            } else {
                return null;
            }
        }
    }

//===================================================================

    @Override
    public List<Integer> findSetmealAndCheckGroup(Integer id) {
        return setmealDao.findSetmealAndCheckGroup(id);
    }

//=========================!!!!!!!!!!!================================

    //编辑套餐
    public void update(Setmeal setmeal, Integer[] checkgroupIds) throws Exception {
        Jedis jedis = jedisPool.getResource();
        Integer sm_id = setmeal.getId();

        //编辑套餐之前先查询数据库，将套餐信息保存到redis中
        Map<String, String> setmeals = jedis.hgetAll("setmeals");
        if (setmeals.size() == 0) {
            saveRedis();
        }

        setmealDao.update(setmeal);
        setmealDao.deleteSetmealAndCheckGroup(sm_id);
        setSetmealAndCheckGroup(sm_id, checkgroupIds);

        //redis中相应的setmeal信息也要做相应修改，直接覆盖原信息
        //先将套餐对应的检查组信息封装到套餐对象中
        ArrayList<CheckGroup> list = new ArrayList<>();
        for (Integer checkgroupId : checkgroupIds) {
            CheckGroup checkGroup = checkGroupDao.findById(checkgroupId);
            list.add(checkGroup);
        }
        setmeal.setCheckGroups(list);
        //将修改完成的setmeal对象转换成json字符串保存到redis中
        String sm_id_str = String.valueOf(sm_id);
        ObjectMapper mapper = new ObjectMapper();
        String setmeal_json = mapper.writeValueAsString(setmeal);

        jedis.hset("setmeals", sm_id_str, setmeal_json);
    }

//===================================================================

    /*建立套餐和检查组之间的关系*/
    public void setSetmealAndCheckGroup(Integer setmealid, Integer[] checkgroupIds) {
        if (checkgroupIds != null) {
            for (Integer checkgroupid : checkgroupIds) {
                Map map = new HashMap();
                map.put("setmeal_id", setmealid);
                map.put("checkgroup_id", checkgroupid);
                setmealDao.setSetmealAndCheckGroup(map);
            }
        }
    }

//===================================================================

    /*移动端*/
    //查询所有套餐信息
    public List<Setmeal> mobileFindAll() throws IOException {

        //查询所有套餐前先去redis中取套餐信息，若不存在再查询mysql数据库
        Jedis jedis = jedisPool.getResource();
        ObjectMapper mapper = new ObjectMapper();

        Map<String, String> sm_info = jedis.hgetAll("setmeals");
        if (sm_info.size() > 0) {
            //redis中有套餐信息，则直接从redis中获取套餐信息
            List<Setmeal> list = new ArrayList<>();

            for (String key : sm_info.keySet()) {
                String setmeal_json = sm_info.get(key);

                //将setmeal字符串反序列化成java对象并装到list集合中
                Setmeal setmeal = mapper.readValue(setmeal_json, Setmeal.class);
                list.add(setmeal);
            }
            System.out.println("从redis中获取所有套餐信息-----mobileFindAll");
            return list;

        } else {
            //操作t_setmeal表，查询结果没有List<CheckGroup>字段,redis中获取的setmeal则有
            saveRedis();
            return setmealDao.mobileFindAll();
        }
    }


    @Override
    public Setmeal find(Integer id) {
        Setmeal setmeal = setmealDao.find(id);
        return setmeal;
    }
}